package gui;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;

public class AssociaClassesEMetodosANomes 
{
	private HashMap<String, Class> nomesDeClassesEObjetosClass;
	private LinkedList<ClasseEMetodos> classesEMetodosAssociados;
	
	public AssociaClassesEMetodosANomes(LinkedList<ClasseEMetodos> classesEMetodosDoProjeto)
	{
		this.nomesDeClassesEObjetosClass = new HashMap<String, Class>();
		this.classesEMetodosAssociados = classesEMetodosDoProjeto;
		for(int i = 0; i < classesEMetodosDoProjeto.size(); i++)
		{
			ClasseEMetodos classeEMetodoDoProjeto = classesEMetodosDoProjeto.get(i);
			Class classeDoProjeto = classeEMetodoDoProjeto.getClasse();
			String nomeClasseDoProjeto = classeDoProjeto.getName();
			nomesDeClassesEObjetosClass.put(nomeClasseDoProjeto, classeDoProjeto);
		}
	}
	
	public Class pegarClasseDeNome(String nomeDaClasse)
	{
		return nomesDeClassesEObjetosClass.get(nomeDaClasse);
	}
	
	
	/**
	 * Dado o nome de uma classe(nome simples, sem pacotes), o sistema irah procurar pelas declaracoes
	 * de metodos associadas a classe em todas as classes do projeto e retorna-las pra quem chamou o metodo.
	 * @param nomeClasse nome da classe(simple name, sem pacotes) em que se deseja pegar a declaracao de metodo
	 * @return lista com as declaracoes de metodos da classe de nome especificado ou null caso nao
	 * seja possivel encontrar a classe no projeto
	 */
	public LinkedList<DeclaracaoDeMetodo> pegarMetodosDeClasse(String nomeClasse)
	{
		for(int i = 0; i < classesEMetodosAssociados.size(); i++)
		{
			ClasseEMetodos classeEMetodoDoProjeto = classesEMetodosAssociados.get(i);
			Class classeDoProjeto = classeEMetodoDoProjeto.getClasse();
			String nomeClasseNoProjeto = classeDoProjeto.getName();
			
			if(nomeClasseNoProjeto.compareTo(nomeClasse) == 0)
			{
				/*achamos a instancia do objeto Class relacionado a esse nome! vamos pegar suas
				 * declaracoes de metodos?
				 */
				LinkedList<DeclaracaoDeMetodo> declaracoesDeMetodoDaClasse = classeEMetodoDoProjeto.getDeclaracaoDosMetodos();
				return declaracoesDeMetodoDaClasse;
			}
		}
		
		//nao conseguimos achar a classe com esse nome no projeto, muito menos as declaracoes de metodos...
		return null;
	}
	
	/**
	 * dado o nome de uma classe(classe carregada previamente pelo sistema), o metodo vai achar os cabecalhos
	 * de todos os metodos dessa classe e retornara em uma lista
	 * @param nomeClasse nome da classe(nome simples, sem pacotes) em que se deseja saber os cabecalhos dos metodos.
	 * @return lista com os cabecalhos dos metodos da classeou lista vazia se a classe nao tiver
	 * metodos ou nao conseguir ser achada.
	 */
	public LinkedList<String> pegarCabecalhosDeMetodosDeUmaClasse(String nomeClasse)
	{
		LinkedList<String> cabecalhosMetodosDaClasse = new LinkedList<String>();
		LinkedList<DeclaracaoDeMetodo> metodosDaClasse = this.pegarMetodosDeClasse(nomeClasse);
		if(metodosDaClasse != null)
		{
			for(int i = 0; i < metodosDaClasse.size(); i++)
			{
				DeclaracaoDeMetodo declaracaoDeMetodoDaClasse = metodosDaClasse.get(i);
				String cabecalhoMetodoDaClasse = declaracaoDeMetodoDaClasse.getCabecalhoDoMetodo();
				cabecalhosMetodosDaClasse.add(cabecalhoMetodoDaClasse);
			}
		}
		
		return cabecalhosMetodosDaClasse;
	}
	
	
	
	/**
	 * dado o cabecalho de um metodo, a operacao retorna o objeto DeclaracoDeMetodo correspondente se
	 * este se encontra nas classes carregadas do projeto
	 * @param cabecalhoDoMetodo cabecalho do metodo que deseja se
	 * encontrar a instancia
	 * @return instancia da declaracao de metodo de nome especificado ou null caso nao seja encontrado
	 */
	public DeclaracaoDeMetodo pegarDeclaracaoDeMetodoDeNome(String cabecalhoDoMetodo, String nomeClasseAssociadaAoMetodo)
	{
		for(int i = 0; i < classesEMetodosAssociados.size(); i++)
		{
			ClasseEMetodos classeEMetodoAssociado = classesEMetodosAssociados.get(i);
			/*vamos agora extrair as declaracoes de metodos dessa classe e procurar em cada metodo
			 * se o cabecaho bae com o especificado no parametro
			 */
			if(nomeClasseAssociadaAoMetodo.compareTo(classeEMetodoAssociado.getClasse().getName()) == 0)
			{
				LinkedList<DeclaracaoDeMetodo> metodosDaClasse = classeEMetodoAssociado.getDeclaracaoDosMetodos();
				for(int j = 0; j < metodosDaClasse.size(); j++)
				{
					DeclaracaoDeMetodo metodoDaClasse = metodosDaClasse.get(j);
					System.out.println("<<<<<<<<<<<<<<<<cabecalhoMetodo="+ metodoDaClasse.getCabecalhoDoMetodo() +">>>>>>>>>>>>>>>>>>>>>");
					//essa declaracao de metodo tem o mesmo cabecalho que o informado no parametro do metodo?
					if(cabecalhoDoMetodo.compareTo(metodoDaClasse.getCabecalhoDoMetodo()) == 0)
					{
						//achamos o objeto Method de mesmo cabecalho associado!
						System.out.println("achamos o Method de mesmo cabecalho!!!!");
						return metodoDaClasse;
					}
				}
			}
			
		}
		
		//nao achamos nenhma correspondencia com esse cabecalho
		System.out.println("nao achamos nenhma correspondencia com esse cabecalho:" + cabecalhoDoMetodo);
		return null;
	}
	
	/**
	 * dado o cabecalho de um metodo, a operacao retorna o objeto Method correspondente se
	 * este se encontra nas classes carregadas do projeto
	 * @param cabecalhoDoMetodo cabecalho do metodo que deseja se
	 * encontrar a instancia
	 * @return instancia do metodo de nome especificado ou null caso nao seja encontrado
	 */
	public Method pegarMetodoDeNome(String cabecalhoDoMetodo, String nomeClasseAssociadaAoMetodo)
	{
		DeclaracaoDeMetodo declaracaoMetodoDoCabecalho = this.pegarDeclaracaoDeMetodoDeNome(cabecalhoDoMetodo, nomeClasseAssociadaAoMetodo); 
		
		if(declaracaoMetodoDoCabecalho != null)
		{
			return declaracaoMetodoDoCabecalho.getMetodoAssociado();
		}
		else
		{
			return null;
		}
			
	}
	

}
